package cn.iocoder.yudao.module.shop.category.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.api.shop.category.eums.ShopCategoryCodeEnum;
import cn.iocoder.yudao.module.shop.category.pojo.bo.ShopCategoryCodeBO;
import cn.iocoder.yudao.module.shop.category.pojo.po.ShopCategory;
import cn.iocoder.yudao.module.shop.category.pojo.vo.ShopCategoryDepositReqVO;
import cn.iocoder.yudao.module.shop.category.pojo.vo.ShopCategoryListReqVO;
import cn.iocoder.yudao.module.shop.category.pojo.vo.ShopCategoryPageReqVO;
import cn.iocoder.yudao.module.shop.category.pojo.vo.ShopCategorySaveReqVO;
import jakarta.validation.Valid;

import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.module.api.shop.ErrorCodeConstants.SHOP_INFO_CATEGORY_NOT_FIRST_LEVEL;
import static cn.iocoder.yudao.module.shop.category.pojo.po.ShopCategory.PARENT_ID_ROOT;

/**
 * 行业类目 Service 实现类
 *
 * @author 山野羡民（1032694760@qq.com）
 */
public interface ShopCategoryService {

    /**
     * 获得主营类目标识列表
     *
     * @return 主营类目标识列表
     */
    List<ShopCategoryCodeBO> getAllCode();

    /**
     * 创建行业类目
     *
     * @param createReqVO 创建信息
     * @return 编号
     */
    Long createCategory(@Valid ShopCategorySaveReqVO createReqVO);

    /**
     * 更新行业类目
     *
     * @param updateReqVO 更新信息
     */
    void updateCategory(@Valid ShopCategorySaveReqVO updateReqVO);

    /**
     * 更新保证金
     *
     * @param updateReqVO 更新信息
     */
    void updateDeposit(@Valid ShopCategoryDepositReqVO updateReqVO);

    /**
     * 删除行业类目
     *
     * @param id 编号
     */
    void deleteCategory(Long id);

    /**
     * 获得行业类目
     *
     * @param id 编号
     * @return 行业类目
     */
    ShopCategory getCategory(Long id);

    /**
     * 校验行业类目是否存在且启用
     *
     * @param id 分类编号
     * @return 行业类目
     */
    ShopCategory validateCategory(Long id);

    /**
     * 校验是否是一级行业类目
     */
    default ShopCategory validateFirstLevelCategory(Long id) {
        ShopCategory categoryDO = validateCategory(id);
        if (!Objects.equals(categoryDO.getParentId(), PARENT_ID_ROOT)) {
            throw exception(SHOP_INFO_CATEGORY_NOT_FIRST_LEVEL);
        }
        return categoryDO;
    }

    /**
     * 获得行业类目的层级
     *
     * @param id 编号
     * @return 行业类目的层级
     */
    Integer getCategoryDepth(Long id);

    /**
     * 获得行业类目列表
     *
     * @return 行业类目列表
     */
    List<ShopCategory> getAllCategoryList();

    /**
     * 获得行业类目列表
     *
     * @param listReqVO 查询条件
     * @return 行业类目列表
     */
    List<ShopCategory> getCategoryList(ShopCategoryListReqVO listReqVO);

    /**
     * 获得行业类目列表
     *
     * @param ids 行业类目编号的数组
     * @return 行业类目列表
     */
    List<ShopCategory> getCategoryList(Set<Long> ids);

    /**
     * 获得行业类目 Map
     *
     * @param ids 行业类目编号的数组
     * @return 行业类目 Map
     */
    default Map<Long, ShopCategory> getCategoryMap(Set<Long> ids) {
        List<ShopCategory> list = getCategoryList(ids);
        return convertMap(list, ShopCategory::getId);
    }

    /**
     * 获得开启状态的一级行业类目列表
     *
     * @return 行业类目列表
     */
    default List<ShopCategory> getEnableRootCategoryList() {
        return getEnableCategoryList(PARENT_ID_ROOT);
    }

    /**
     * 获得开启状态的行业类目列表
     *
     * @param parentId 父级编号
     * @return 行业类目列表
     */
    List<ShopCategory> getEnableCategoryList(Long parentId);

    /**
     * 获得开启状态的行业类目列表
     *
     * @param parentCode 父级编号
     * @return 行业类目列表
     */
    List<ShopCategory> getEnableCategoryList(String parentCode);

    /**
     * 获得开启状态的行业类目列表，指定编号
     *
     * @param ids 行业类目编号数组
     * @return 行业类目列表
     */
    List<ShopCategory> getEnableCategoryList(Collection<Long> ids);

    /**
     * 校验行业类目是否有效。如下情况，视为无效：
     * 1. 行业类目编号不存在
     * 2. 行业类目被禁用
     * 3. 行业类目层级校验，必须使用第二级的行业类目及以下
     *
     * @param ids 行业类目编号数组
     */
    void validateCategoryList(Collection<Long> ids);

    /**
     * 获得类目分页
     */
    PageResult<ShopCategory> getCategoryPage(ShopCategoryPageReqVO reqVO);

    /**
     * 获得指定类目的所有后代类目
     *
     * @param parentIds 类目编号
     * @param status    启用/关闭
     * @return 后代类目列表
     */
    List<ShopCategory> getDescendentCategoryList(Collection<Long> parentIds, Integer status);

    /**
     * 根据类目标识获得指定类目
     *
     * @param status 启用/关闭 {@link CommonStatusEnum}
     * @return 类目
     */
    ShopCategory getCategory(String code, Integer status);

    /**
     * 获得所有子类目，从缓存中
     *
     * @param parentId 父类目编号
     * @param status   启用/关闭 {@link CommonStatusEnum}
     * @return 子类目列表
     */
    Set<Long> getDescendentCategoryIdsFromCache(Long parentId, Integer status);

    /**
     * 获得开启状态的类目列表
     *
     * @param parentIds 父类目编号数组
     * @return 类目列表
     */
    default List<ShopCategory> getEnableDescendentCategoryList(Set<Long> parentIds) {
        return getDescendentCategoryList(parentIds, CommonStatusEnum.ENABLE.getStatus());
    }

    /**
     * 获得开启状态的类目列表
     *
     * @param parentCode 父类目标识数组
     * @param includeParent 是否包含父类目
     * @return 类目列表
     */
    default List<ShopCategory> getEnableDescendentCategoryList(String parentCode, Boolean includeParent) {
        if (StrUtil.isEmpty(parentCode)) {
            return getEnableDescendentCategoryList(CollUtil.newHashSet(PARENT_ID_ROOT));
        }
        List<ShopCategory> list = new ArrayList<>();
        ShopCategory parent = getCategory(parentCode, CommonStatusEnum.ENABLE.getStatus());
        if (parent != null) {
            if (Boolean.TRUE.equals(includeParent)) {
                list.add(0, parent);
            }
            list.addAll(getEnableDescendentCategoryList(CollUtil.newHashSet(parent.getId())));
        }
        return list;
    }

    default List<ShopCategory> getEnableDescendentCategoryList(Long parentId) {
        return getEnableDescendentCategoryList(CollUtil.newHashSet(parentId));
    }

    Long getParentCategoryId(Long id);

    /**
     * 按生活商圈获取行业类目编号
     */
    default Set<Long> getIdsByO2O() {
        List<ShopCategory> categoryDOS = getEnableRootCategoryList();
        if (CollUtil.isEmpty(categoryDOS)) {
            return Collections.emptySet();
        }
        Set<String> o2oCodes = ShopCategoryCodeEnum.getO2oCodes();
        return categoryDOS.stream().filter(categoryDO -> o2oCodes.contains(categoryDO.getCode()))
                .map(ShopCategory::getId).collect(Collectors.toSet());
    }

    /**
     * 获取行业类目下的店铺数量
     *
     * @param categoryId 类目编号
     * @return 店铺数量
     */
    Long getShopCountByCategoryId(Long categoryId);

    /**
     * 获取行业类目编号
     *
     * @param supplyRelatedId 供应方关联编号
     * @return 行业类目
     */
    ShopCategory getBySupplyRelatedId(Long supplyRelatedId);

}
